#include "Camera.h"
#include "./Transfer.cpp"

    // 初始化摄像头
int Camera::init(bool useDshow = false){

    // 编码动态分配
    this->pFmtCtx = avformat_alloc_context();
    // this->pFmtCtx->probesize = 1000;
    // this->pFmtCtx->duration = 10 * AV_TIME_BASE;

    // 初始化网络
    avformat_network_init();
    // 注册设备
    avdevice_register_all();

#ifdef _WIN32
// Win
    if(useDshow)
    {   
        // DShow
        AVInputFormat *pIptFmt = av_find_input_format("dshow");
        
        ostringstream win32dev;
        win32dev << "video=" << this->_Setting.DevFilePath;

        if(avformat_open_input(&pFmtCtx, win32dev.str(), pIptFmt, Null))
        {
            cerr << "无法打开您的设备："<<  this->_Setting.DevFilePath;
            return -1;
        }
        else{
        // vfwcap

        }
    }
#endif

#ifdef linux
// Linux
    const AVInputFormat *pIptFmt = av_find_input_format("v4l2");

    if(avformat_open_input(
                &pFmtCtx,
                (this->_Setting.DevFilePath).c_str(),
                pIptFmt, NULL
                ))
    {
            cerr << "could not open your device: "<<  this->_Setting.DevFilePath;
            return -1;
    }

#endif

    // 输出媒体文件信息
    cout << "————————————————————媒体信息—————————————————————" << endl;
    av_dump_format(this->pFmtCtx, 0, NULL, 0);
    cout << "—————————————————————————————————————————————————" << endl;

    // 识别流
    if(avformat_find_stream_info(this->pFmtCtx, NULL) < 0)
    {
        cerr << "Could not find stream information" << endl;
        return -1;
    }


    this->pCodecCtx = avcodec_alloc_context3(NULL);
    return 1;
}

// 释放
void Camera::release(){

    avcodec_free_context(&this->pCodecCtx);
    avcodec_close(this->pCodecCtx);

    if (this->pFmtCtx) {
        avformat_close_input(&this->pFmtCtx);
        avformat_free_context(this->pFmtCtx);
        this->pFmtCtx = NULL;
    }
}


int Camera::cheese()
{   
    // 设置帧的位数
    int videoindex = -1;

    // 寻 帧
    for( int i = 0; i< this->pFmtCtx->nb_streams; i++)
    {
        if(this->pFmtCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO )
        {
            videoindex = i;
            break;
        }
    }

    // 判断帧是否变化 ? 继续 : 输出
    if( videoindex == -1 )
    {
        cerr << "Could not find video stream" << endl;
        return -1;
    }


    // 自动解码操作
    if (avcodec_parameters_to_context(
            this->pCodecCtx, this->pFmtCtx->streams[videoindex]->codecpar) < 0
        )
    {
        cerr << "Failed to copy codec parameters to codec context" << endl;
        return -1;
    }
    cout << this->pCodecCtx->codec_id << endl;
    const AVCodec *pCodec = avcodec_find_decoder(this->pCodecCtx->codec_id);

    /*
        FFmpegV3 Old 写法 来自：CSDN 雷霄骅
    	pCodecCtx = pFormatCtx->streams[videoindex]->codec;
	    pCodec = avcodec_find_decoder(pCodecCtx->codec_id)
    */

    if(pCodec == NULL)
    {
        cerr << "Could not find Codec" << endl;
        return -1;
    }
    if(avcodec_open2(this->pCodecCtx, pCodec, NULL) < 0)
    {
        cerr << "Could not open Codec" << endl;
        return -1;
    }

    // 图像
    AVFrame	*pFrame = av_frame_alloc();
    pFrame->format = AV_PIX_FMT_YUYV422;
    // pFrame->format = ;
    AVPacket *Packet = av_packet_alloc();
    sleep(2);
    // Cheese 拍照
    cout  << this->_Setting.DevFilePath << ": Say Cheese!"      << endl;
    sleep(2);

    std::ofstream outputFile("output.jpg", std::ios::binary);
    
    while(
        av_read_frame( this->pFmtCtx, Packet) >= 0
    )
    {
        if(Packet->stream_index == videoindex){
            avcodec_send_packet(this->pCodecCtx, Packet);
            avcodec_receive_frame(this->pCodecCtx, pFrame);

                if (outputFile) {

                    convertFrameToYUYV(pFrame, outputFile);
                }


        }
        av_packet_unref(Packet);
        break; // 拍照
    }

    outputFile.close();

    av_packet_free(&Packet);
    av_frame_free(&pFrame);
    cout << "Cheese Success" << endl;
    return 1;
}


void Camera::version(){
    cout << "VERSION DETAIL"                                    << endl
         << "Device : "         << this->_Setting.DevFilePath   << endl
         << "Resolution : "     << this->_Setting.Resolution    << endl;

    ostringstream util,codec;

    cout << "Program version: " << "0.0.02"                     << endl; 

    cout << "FFmpeg version: "  <<  av_version_info()           << endl;

    util << AV_VERSION_MAJOR(avutil_version()) 
         << AV_VERSION_MINOR(avutil_version()) 
         << AV_VERSION_MICRO(avutil_version());
    cout << "Libavutil version: " << util.str() << endl;

    codec << AV_VERSION_MAJOR(avcodec_version()) 
          << AV_VERSION_MINOR(avcodec_version())
          << AV_VERSION_MICRO(avcodec_version());
    cout << "Libavcodec version: " << codec.str() << endl;

}


// Future
int Camera::start_REC()
{
    cout<<"this is start"<< endl;
    return 0;
}

int Camera::stop_REC()
{
    cout<<"this is stop"<< endl;
    return 0;
}

int Camera::status_REC(string DevFilePath)
{
    cout<<"this is "<< DevFilePath << endl;
    return 0;
}
